package com.ryan.plugin;

import com.intellij.ide.BrowserUtil;
import com.intellij.notification.*;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.ryan.plugin.output.JSON;
import com.ryan.plugin.store.Store;
import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

public class MainAction extends AnAction {

    private Store store;
    private ClassAnalyzer analyzer;
    private final Object requester = new Object();

    @Override
    public void actionPerformed(@NotNull AnActionEvent event) {
        Project project = event.getProject();
        VirtualFile[] files = ProjectRootManager.getInstance(Objects.requireNonNull(project)).getContentRoots();
        List<VirtualFile> vfs = prepareFolders(files);

        ChooseDialog dialog = new ChooseDialog(project, vfs, selected -> createBackgroundTask(event, selected));
        dialog.show();
    }

    private void createBackgroundTask(AnActionEvent event, List<VirtualFile> vfs) {
        Project project = event.getProject();
        ProgressManager.getInstance().run(new Task.Backgroundable(project, "Analyzing") {
            @SuppressWarnings("UnstableApiUsage")
            @Override
            public void run(@NotNull ProgressIndicator indicator) {
                indicator.setIndeterminate(false);

                store = Store.getInstance();
                if (analyzer == null) {
                    analyzer = new ClassAnalyzer();
                }

                analyzer.prepare(event);

                for (VirtualFile vf : vfs) {
                    String path = vf.getPath();
                    path += "/src/main/java/";
                    FileTraverse.traverse(analyzer, new File(path), (file, finish) -> {
                        if (!finish) indicator.setText("Analyzing: " + file.getAbsolutePath());
                    });
                }

                store.checkIfFromSource();

                ApplicationManager.getApplication().invokeLaterOnWriteThread(() ->
                        ApplicationManager.getApplication().runWriteAction(() -> {
                            VirtualFile path = saveToFile(event);
                            if (path == null) return;
                            createNotification(project, path);
                            store.reset();
                        }));
                indicator.setIndeterminate(true);
            }
        });
    }

    private List<VirtualFile> prepareFolders(VirtualFile[] files) {
        List<VirtualFile> vfs = new ArrayList<>();
        for (int i = 0; i < files.length; i++) {
            if (i != 0) vfs.add(files[i]);
        }
        return vfs;
    }

    private VirtualFile saveToFile(AnActionEvent event) {
        String name = "output.json";
        VirtualFile project = Objects.requireNonNull(event.getProject()).getBaseDir();
        try {
            VirtualFile json = project.findChild(name);
            if (json == null) {
                json = project.createChildData(requester, name);
            }

            json.setWritable(true);
            json.setBinaryContent(JSON.toJson(store).getBytes(StandardCharsets.UTF_8));

            return json;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    private void createNotification(Project project, VirtualFile result) {
        NotificationGroup GROUP_DISPLAY_ID_INFO =
                new NotificationGroup("CodeAnalyzer",
                        NotificationDisplayType.BALLOON, true);
        Notification notification = GROUP_DISPLAY_ID_INFO
                .createNotification("Results have been saved to file: " + result,
                        NotificationType.INFORMATION);
        notification.addAction(new NotificationAction("Open") {
            @Override
            public void actionPerformed(@NotNull AnActionEvent anActionEvent, @NotNull Notification notification) {
                BrowserUtil.browse(result);
            }
        });

        notification.addAction(new NotificationAction("Open in directory") {
            @Override
            public void actionPerformed(@NotNull AnActionEvent anActionEvent, @NotNull Notification notification) {
                BrowserUtil.browse(result.getParent());
            }
        });
        Notifications.Bus.notify(notification, project);
    }
}
